package ch.zbw.pra.sysventory.business.businessObject.scan;

import java.io.Serializable;
import java.util.List;
import java.util.concurrent.Callable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.zbw.pra.sysventory.model.Computer;
import ch.zbw.pra.sysventory.model.HardDisk;
import ch.zbw.pra.sysventory.model.Nic;
import ch.zbw.pra.sysventory.model.OperatingSystem;
import ch.zbw.pra.sysventory.model.Printer;
import ch.zbw.pra.sysventory.model.Processor;
import ch.zbw.pra.sysventory.model.Software;

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.jacob.com.EnumVariant;
import com.jacob.com.Variant;

/**
 * Scant den übergebenen host nach hostname, sid, ram, typ sowie os, processor,
 * softwares, nics und printers
 * 
 * @author Ralph Koster
 */

public class ScanComputerBusinessObject implements Callable<Computer>, Serializable {

	private static final long serialVersionUID = 6868935693559322495L;
	private static Logger LOG = LoggerFactory.getLogger(ScanComputerBusinessObject.class);
	
	private ActiveXComponent axWMI;
	private EnumVariant enumVariant;
	private Variant vCollection;
	private Dispatch item;
	private String query;
	private String host;
	private String computerHostName;
	private String computerSid;
	private String computerRam;
	private String computerType;
	private OperatingSystem operatingSystem;
	private Processor processor;
	private List<HardDisk> hardDisks;
	private List<Software> softwares;
	private List<Nic> nics;
	private List<Printer> printers;
	private boolean threadFinish;

	private Computer computer;

	public ScanComputerBusinessObject(String host) {
		this.host = host;
	}
	
	@Override
	public Computer call() throws Exception {
		return scanComputer();
	}

	public Computer scanComputer() {
		try {
			String connectStr = String.format("winmgmts:\\\\%s\\root\\CIMV2",
					host);

			axWMI = new ActiveXComponent(connectStr);
			
			readDataFromClassWIN32_ComputerSystem();
			readDataFromClassWIN32_UserAccount();
			scanOtherComputerData(host);
			
			LOG.debug("Computer found: " + computerHostName + " SID: "
					+ computerSid + " RAM in MB: " + computerRam
					+ " Computertyp: " + computerType);
			
			computer = new Computer(computerHostName, computerSid, computerRam,
					computerType, operatingSystem, processor, hardDisks, softwares, nics, printers);
		} catch (Exception e) {
			LOG.debug("Failed to load computer data on host: " + host);
		}
		return computer;
	}

	private void readDataFromClassWIN32_ComputerSystem() {
		query = "SELECT * FROM Win32_ComputerSystem";
		vCollection = axWMI.invoke("ExecQuery", new Variant(query));
		enumVariant = new EnumVariant(vCollection.toDispatch());
		item = null;
		while (enumVariant.hasMoreElements()) {
			item = enumVariant.nextElement().toDispatch();
			// Dispatch.call returns a Variant which we can convert to a
			// java form.
			computerHostName = Dispatch.call(item, "Name").toString();
			long ramTemp = Long
					.valueOf(
							(Dispatch.call(item, "TotalPhysicalMemory"))
									.toString()).longValue();

			final long MEGABYTE = 1024L * 1024L;
			computerRam = String.valueOf(ramTemp / MEGABYTE);

			int typ = 0;
			try {
				String strTyp = Dispatch.call(item, "PCSystemType")
						.toString();
				typ = Integer.parseInt(strTyp);
			} catch (Exception e) {
				LOG.debug("Failed to load pc system type on host: " + host);
			}

			switch (typ) {
			case 0:
				computerType = "Unspecified";
				break;
			case 1:
				computerType = "Desktop";
				break;
			case 2:
				computerType = "Mobile";
				break;
			case 3:
				computerType = "Workstation";
				break;
			case 4:
				computerType = "Enterprise Server";
				break;
			case 5:
				computerType = "Mall Office and Home Office (SOHO) Server";
				break;
			case 6:
				computerType = "Appliance PC";
				break;
			case 7:
				computerType = "Performance Server";
				break;
			case 8:
				computerType = "Maximum";
				break;
			default:
				computerType = "Unspecified";
				break;
			}
		}
	}
	
	private void readDataFromClassWIN32_UserAccount() {
		query = "SELECT * from Win32_UserAccount WHERE Name='Administrator' AND LocalAccount=True";
		vCollection = axWMI.invoke("ExecQuery", new Variant(query));
		enumVariant = new EnumVariant(vCollection.toDispatch());
		item = null;
		while (enumVariant.hasMoreElements()) {
			item = enumVariant.nextElement().toDispatch();
			computerSid = Dispatch.call(item, "SID").toString();
			if (computerSid.length() > 0 && computerSid.indexOf("-") > 0) {
				computerSid.substring(0, computerSid.lastIndexOf("-"));
			}
		}
	}

	public void scanOtherComputerData(String host) {
		ScanHardDiskBusinessObject hardDisk = new ScanHardDiskBusinessObject();
		hardDisks = hardDisk.getAllHardDisksFromHost(host);
		
		ScanOperatingSystemBusinessObject scanOs = new ScanOperatingSystemBusinessObject();
		operatingSystem = scanOs.getOperatingSystemFromHost(host);

		ScanProcessorBusinessObject scanProcessor = new ScanProcessorBusinessObject();
		processor = scanProcessor.getProcessorFromHost(host);

		ScanSoftwareBusinessObject scanSoftware = new ScanSoftwareBusinessObject();
		softwares = scanSoftware.getAllSoftwareFromHost(host);

		ScanNicBusinessObject scanNic = new ScanNicBusinessObject();
		nics = scanNic.getAllNicFromHost(host);

		ScanPrinterBusinessObject scanPrinter = new ScanPrinterBusinessObject();
		printers = scanPrinter.getPrinterFromHost(host);
	}

	public boolean isThreadFinish() {
		return threadFinish;
	}

	public void setThreadFinish(boolean threadFinish) {
		this.threadFinish = threadFinish;
	}
}
